package com.ys.entity.base;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.springframework.context.ApplicationContext;
import org.springframework.web.context.ContextLoader;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.bo.util.MapUtil;
import com.ys.annotation.YsField;
import com.ys.enume.sys.TsDictionaryForFieldEnum;
import com.ys.mapper.business.CommonMapper;

public abstract class BaseEntity<E extends BaseEntity<E>> {
	
	public static ApplicationContext _ys_ac;

//	public SysCommonMapper daoSys;

	public CommonMapper _ys_dao;
	
//	private String _ys_field;
	
	private List<String> _ys_fields = new ArrayList<String>();
	private boolean _ys_isFieldOnly = false;
	private String _ys_tableName = null;
	
	private List<String> _ys_diyConfs= new ArrayList<String>();
	
	private List<String> _ys_outerJoins= new ArrayList<String>();
	
	private List<String> _ys_innerJoins= new ArrayList<String>();
	
	private List<String> _ys_listUkey= new ArrayList<String>();
	
	private String _ys_ukey= "";
	
	public E queryFirst() {
		
		this._ys_size = 1;
		this._ys_page = 0;
		
		List<E> list = queryList();
		if (list != null && list.size() > 0) {
			return list.get(0);
		}
		return null;
	};
	
	@SuppressWarnings("unchecked")
	public List<E> queryList() {
		E entity = (E) this;
		
		if (_ys_ac == null) {
			_ys_ac = ContextLoader.getCurrentWebApplicationContext();
		}

//		if (daoSys == null) {
//			daoSys = (SysCommonMapper) ac.getBean("sysCommonMapper");
//		}
		
		try {
			
			List<Map<String, Object>> listMap = this.queryMap();
			
			List<E> listEntity = new ArrayList<E>();
			for(Map<String, Object> map : listMap) {
				E activity = (E) MapUtil.mapToObject(map, entity.getClass());
				listEntity.add(activity);
			}
			return listEntity;
		} catch (Exception e) {
			e.printStackTrace();
		}

		return null;
	};
	
	public List<Map<String, Object>> queryMap() {
		
		if (_ys_ac == null) {
			_ys_ac = ContextLoader.getCurrentWebApplicationContext();
		}

//		if (daoSys == null) {
//			daoSys = (SysCommonMapper) ac.getBean("sysCommonMapper");
//		}

		if (_ys_dao == null) {
			_ys_dao = (CommonMapper) _ys_ac.getBean("commonMapper");
		}
		
		try {
			
//			if (tableAllName.startsWith("`sys_")) {
//				return daoSys.searchMap(generateSearchSql());
//			} else {
//				return dao.searchMap(generateSearchSql());
//			}
				
			List<String> listField = generateListField();
			Pager pager = generatePager();
			List<String> listCondition = generateCondition();
			List<String> listOuterJoin = this._ys_outerJoins;
			List<String> listUkey = this._ys_listUkey;
			return _ys_dao.searchMap2(listField, pager, listOuterJoin, listCondition, this._ys_ukey, listUkey);
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		return null;
	};
	
	public List<Map<String, Object>> queryMapNoOrder() {
		
		if (_ys_ac == null) {
			_ys_ac = ContextLoader.getCurrentWebApplicationContext();
		}

//		if (daoSys == null) {
//			daoSys = (SysCommonMapper) ac.getBean("sysCommonMapper");
//		}

		if (_ys_dao == null) {
			_ys_dao = (CommonMapper) _ys_ac.getBean("commonMapper");
		}
		
		try {
			
//			if (tableAllName.startsWith("`sys_")) {
//				return daoSys.searchMap(generateSearchSql());
//			} else {
//				return dao.searchMap(generateSearchSql());
//			}
				
			List<String> listField = generateListField();
			Pager pager = generatePager();
			pager.setOrderBy(null);
			List<String> listCondition = generateCondition();
			List<String> listOuterJoin = this._ys_outerJoins;
			List<String> listUkey = this._ys_listUkey;
			return _ys_dao.searchMap2(listField, pager, listOuterJoin, listCondition, this._ys_ukey, listUkey);
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		return null;
	};
	
	public Map<String, Object> queryFirstMap() {
		
		this._ys_size = 1;
		this._ys_page = 0;
		
		List<Map<String, Object>> list = queryMap();
		if (list != null && list.size() > 0) {
			return list.get(0);
		}
		return null;
	};
	
	public int count() {
		
		if (_ys_ac == null) {
			_ys_ac = ContextLoader.getCurrentWebApplicationContext();
		}

//		if (daoSys == null) {
//			daoSys = (SysCommonMapper) ac.getBean("sysCommonMapper");
//		}

		if (_ys_dao == null) {
			_ys_dao = (CommonMapper) _ys_ac.getBean("commonMapper");
		}
		
//		if (tableAllName.startsWith("`sys_")) {
//			return daoSys.countInteger(generateCountSql());
//		} else {
			Pager pager = generatePager();
			List<String> listCondition = generateCondition();
			List<String> listOuterJoin = this._ys_outerJoins;
			return _ys_dao.countInteger2(pager, listOuterJoin, listCondition);
//		}

	};
	
	public BigDecimal sumDecimal() {
		
		if (_ys_ac == null) {
			_ys_ac = ContextLoader.getCurrentWebApplicationContext();
		}

//		if (daoSys == null) {
//			daoSys = (SysCommonMapper) ac.getBean("sysCommonMapper");
//		}

		if (_ys_dao == null) {
			_ys_dao = (CommonMapper) _ys_ac.getBean("commonMapper");
		}
		
//		if (tableAllName.startsWith("`sys_")) {
//			return daoSys.sumBigDecimal(generateSumSql());
//		} else {
		List<String> listField = generateListField();
		Pager pager = generatePager();
		List<String> listCondition = generateCondition();
		List<String> listOuterJoin = this._ys_outerJoins;
			return _ys_dao.sumBigDecimal2(listField, pager, listOuterJoin, listCondition);
//		}

	};
	
	/**
	 * 添加字段
	 * @param field 格式如A.merchant_id AS merchantId
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public E addField(String field) {
		this._ys_fields.add(field);
		this._ys_isFieldOnly = false;
		return (E) this;
	}
	
	/**
	 * 左连接语句，示例：t_merchant B ON A.merchant_id = B.id
	 * @param sql
	 */
	@SuppressWarnings("unchecked")
	public E addLeftJoin(String sql) {
		this._ys_outerJoins.add("LEFT JOIN " + sql + " ");
		return (E) this;
	}
	
	/**
	 * 右连接语句，示例：t_merchant B ON A.merchant_id = B.id
	 * @param sql
	 */
	@SuppressWarnings("unchecked")
	public E addRightJoin(String sql) {
		this._ys_outerJoins.add("RIGHT JOIN " + sql + " ");
		return (E) this;
	}
	
	/**
	 * 清除连接语句，一般用于统计
	 * @param sql
	 */
	@SuppressWarnings("unchecked")
	public E clearLeftJoin() {
		this._ys_outerJoins = new ArrayList<String>();
		return (E) this;
	}
	
	/**
	 * 内连接语句，示例：merchant_account_running B ON B.merchant_id = A.merchant_id
	 * @param sql
	 */
	@SuppressWarnings("unchecked")
	public E addInnerJoin(String sql) {
		this._ys_innerJoins.add("INNER JOIN " + sql + " ");
		return (E) this;
	}
	
	public List<String> generateListField() {
		
		// 设置了只有一个字段，则返回单个字段
		if (this._ys_isFieldOnly == true) {
			return this._ys_fields;
		} else {
			
		
			List<String> listField = new ArrayList<String>();
			
			Class<?> clazz = this.getClass();
			for (; clazz != Object.class; clazz = clazz.getSuperclass()) {
				Field[] fields = clazz.getDeclaredFields();
				for (Field field : fields) {
					YsField attrAnnotation = field.getAnnotation(YsField.class);
					if (attrAnnotation != null) {
						if (attrAnnotation.typeDataBase().equals("bit")) {
							listField.add("A.[" + attrAnnotation.nameDataBase() + "] * 1 AS [" + attrAnnotation.nameJava() + "]");
						} else {
							listField.add("A.[" + attrAnnotation.nameDataBase() + "] AS [" + attrAnnotation.nameJava() + "]");
						}
					}
				}
			}
			
			for (String str : this._ys_fields) {
				listField.add(str);
			}
			
			return listField;
		}
	}
	
	/**
	 * 清空原表字段
	 */
	@SuppressWarnings("unchecked")
	public E clearFieldsSource() {
		this._ys_isFieldOnly = true;
		return (E) this;
	}
	
	/**
	 * 设置字段
	 * @param fields，格式：ifnull(sum(A.detail_real_price,0))，或者A.merchant_id,A.A.merchant_code
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public E setFields(String fields) {
		this._ys_fields = new ArrayList<String>();
		this._ys_fields.add(fields);
		this._ys_isFieldOnly = true;
		return (E) this;
	}
	
	/**
	 * 添加条件
	 * @param condition 格式：A.merchant_id=1
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public E where(String condition) {
		if (condition != null && condition.length() > 0) {
			this._ys_diyConfs.add("(" + condition + ")");
		}
		return (E) this;
	}
	
	/**
	 * 添加条件
	 * @param field 格式：A.merchant_id
	 * @param intVal 格式：1
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public E where(String field, Integer intVal) {
		this._ys_diyConfs.add("(" + field + "=" + intVal + ")");
		return (E) this;
	}
	
	/**
	 * 添加条件
	 * @param field 格式：A.merchant_id
	 * @param strVal 格式：xxxxxx
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public E where(String field, String strVal) {
		this._ys_diyConfs.add("(" + field + "='" + strVal + "')");
		return (E) this;
	}
	
	/**
	 * 生成表名
	 * @return
	 */
	public String generateTableAllName() {
		if (this._ys_tableName != null) {
			return this._ys_tableName;
		} else {
			return this.getClass().getAnnotation(javax.persistence.Table.class).name();
		}
	}
	
	/**
	 * 生成主键名
	 * @return
	 */
	public String generatePrimaryKey() {
		return this.getClass().getAnnotation(javax.persistence.Table.class).catalog();
	}
	
	/**
	 * 生成条件语句，从where到order by之间
	 * @return
	 */
	public List<String> generateCondition() {
		
		List<String> listCondition = new ArrayList<String>();
		//listCondition.add("1=1");
		
		Class<?> clazz = this.getClass();
		for (; clazz != Object.class; clazz = clazz.getSuperclass()) {
			Field[] fields = clazz.getDeclaredFields();
			for (Field field : fields) {
				String name = field.getName();
				if (
						name.startsWith("_ys_")
//						|| "e".equals(name)
						) {
					continue;
				}
				if (!field.isAccessible()) {
					field.setAccessible(true);
				}
				try {
					Object value = field.get(this);
					if (value != null && !"".equals(value)) {
						listCondition.add("A." + name + " = '" + value.toString().replace("#", "").replace("{", "").replace("}", "") + "' ");
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
		
		
		// 拼接自定义搜索
		for (String sql : this._ys_diyConfs) {
			listCondition.add(sql.replace("#", "").replace("{", "").replace("}", ""));
		}
		
		return listCondition;
	}
	
	/**
	 * 生成 order by 语句
	 * @return
	 */
	public Pager generatePager() {
		
		Pager pager = new Pager();
		
		pager.setTableName(generateTableAllName());
		
		if (_ys_orderBy != null && _ys_orderBy.length() > 0) {
			pager.setOrderBy(_ys_orderBy);
		} else {
			pager.setOrderBy("A." + generatePrimaryKey());
		}
		
		if (_ys_size != null) {
			pager.setSize(_ys_size);
			
			if (_ys_page != null) {
				pager.setStart(_ys_page * _ys_size);
			}
		}
		
		return pager;
	}
	
	/**
	 * 生成完整的sql语句（统计）
	 * @return
	 */
	public String generateCountSql() {
		StringBuffer sb = new StringBuffer("select count(1)").append(" ")
		.append("from").append(" ")
		.append(generateTableAllName()).append(" A ");

		// 拼接自定义搜索
		for (String sql : this._ys_outerJoins) {
			sb.append(sql + " ");
		}

		// 拼接自定义搜索
		for (String sql : this._ys_innerJoins) {
			sb.append(sql + " ");
		}
		
//		sb.append(generateCondition()).append(" ").append(generateGroupby());
		sb.append(generateCondition()).append(" ");
		
		return sb.toString();
	}
	
	
	public Integer _ys_size; // 分页用-每页条数
	public Integer _ys_page; // 分页用-起始数
	private String _ys_orderBy; // 排序用-排序字段，值可以是驼峰，也可以是原数据库字段
	
	@SuppressWarnings("unchecked")
	public E setSize(Integer size) {
		this._ys_size = size;
		return (E) this;
	}
	@SuppressWarnings("unchecked")
	public E setPage(Integer page) {
		this._ys_page = page;
		return (E) this;
	}
	@SuppressWarnings("unchecked")
	public E setOrderby(String orderby) {
		this._ys_orderBy = orderby;
		return (E) this;
	}
	@SuppressWarnings("unchecked")
	public E setMainTable(String tableName) {
		this._ys_tableName = tableName;
		return (E) this;
	}
	@SuppressWarnings("unchecked")
	public E setConditions(String conditions) {
		if (conditions == null || conditions.length() == 0) {
			return (E) this;
		}
		JSONArray conditionJA = JSON.parseArray(conditions);
		for (int i = 0; i < conditionJA.size(); i++) {
			JSONObject conditionJO = conditionJA.getJSONObject(i);
			String rangeType = conditionJO.getString("rangeType");
			String field = conditionJO.getString("field");
			
			if (field.startsWith("_ys_")) {
				continue;
			} else if (!field.contains(".")) {
				field = "A." + field;
			}
			
			String value = conditionJO.getString("value");
			if (rangeType.equals(TsDictionaryForFieldEnum.FieldFrontConditionsType.SYSTEM.value)) {
				this._ys_diyConfs.add(field + " = '" + value + "'");
			} else if (rangeType.equals(TsDictionaryForFieldEnum.FieldFrontConditionsType.BOTHLIKE.value)) {
				this._ys_diyConfs.add(field + " like '%" + value + "%'");
			} else if (rangeType.equals(TsDictionaryForFieldEnum.FieldFrontConditionsType.LEFTLIKE.value)) {
				this._ys_diyConfs.add(field + " like '%" + value + "'");
			} else if (rangeType.equals(TsDictionaryForFieldEnum.FieldFrontConditionsType.RIGHTLIKE.value)) {
				this._ys_diyConfs.add(field + " like '" + value + "%'");
			} else if (rangeType.equals(TsDictionaryForFieldEnum.FieldFrontConditionsType.BETWEEN.value)) {
				String[] values = value.split(" ~ ");
				this._ys_diyConfs.add(field + " >= '" + values[0] + "'");
				this._ys_diyConfs.add(field + " <= '" + values[1] + "'");
			} else if (rangeType.equals(TsDictionaryForFieldEnum.FieldFrontConditionsType.HIDDEN.value)) {
				this._ys_diyConfs.add(field + " = '" + value + "'");
			}
		}
		return (E) this;
	}
	@SuppressWarnings("unchecked")
	public E setConditionss(String conditionss) {
		if (conditionss == null || conditionss.length() == 0) {
			return (E) this;
		}
		JSONArray conditionJA = JSON.parseArray(conditionss);
		for (int i = 0; i < conditionJA.size(); i++) {
			JSONObject conditionJO = conditionJA.getJSONObject(i);
			String rangeType = conditionJO.getString("rangeType");
			String code = conditionJO.getString("code");
			
			if (code.startsWith("_ys_")) {
				continue;
			} else if (!code.contains(".")) {
				code = "A." + code;
			}
			
			String value = conditionJO.getString("value");
			if (value == null || value.length() == 0) {
				continue;
			}
			if (rangeType.equals(TsDictionaryForFieldEnum.FieldFrontConditionsType.SYSTEM.value)) {
				this._ys_diyConfs.add(code + " = '" + value + "'");
			} else if (rangeType.equals(TsDictionaryForFieldEnum.FieldFrontConditionsType.BOTHLIKE.value)) {
				this._ys_diyConfs.add(code + " like '%" + value + "%'");
			} else if (rangeType.equals(TsDictionaryForFieldEnum.FieldFrontConditionsType.LEFTLIKE.value)) {
				this._ys_diyConfs.add(code + " like '%" + value + "'");
			} else if (rangeType.equals(TsDictionaryForFieldEnum.FieldFrontConditionsType.RIGHTLIKE.value)) {
				this._ys_diyConfs.add(code + " like '" + value + "%'");
			} else if (rangeType.equals(TsDictionaryForFieldEnum.FieldFrontConditionsType.BETWEEN.value)) {
				String[] values = value.split(" ~ ");
				this._ys_diyConfs.add(code + " >= '" + values[0] + "'");
				this._ys_diyConfs.add(code + " <= '" + values[1] + "'");
			} else if (rangeType.equals(TsDictionaryForFieldEnum.FieldFrontConditionsType.HIDDEN.value)) {
				this._ys_diyConfs.add(code + " = '" + value + "'");
			}
		}
		return (E) this;
	}
	
	@SuppressWarnings("unchecked")
	public E setListUkey(List<String> listUkey) {
		this._ys_listUkey = listUkey;
		return (E) this;
	}
	
	@SuppressWarnings("unchecked")
	public E setUkey(String ukey) {
		this._ys_ukey = ukey;
		return (E) this;
	}
}